/******************************************************************************

	COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2009, 2010.

	This file is part of Maxsi Engine.

	Maxsi Engine is free software: you can redistribute it and/or modify it
	under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or (at your
	option) any later version.

	Maxsi engine is distributed in the hope that it will be useful, but WITHOUT
	ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
	FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
	for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with Maxsi Engine. If not, see <http://www.gnu.org/licenses/>.

	MaxsiEngine.dll
	A general purpose C++ library for the Maxsi Technology Project.

	MaxsiServer.h
	Basic Winsock Functionallity for server handling.

******************************************************************************/

#ifndef MaxsiServer_H
#define MaxsiServer_H

#include <time.h>

// Todo: Clean up this file, remove old commented-out code.

BeginMaxsiNamespace

//#define	ME_Server_Version	_MESTR("Application/x-MaxsiEngineServer/1.0 v" __DATE__)


//#define MAX_IN_BUFFER_SIZE	1048576

#define STATE_DEAD			0
#define STATE_NOTCONNECTED	0
#define	STATE_ACCEPTING		1
#define	STATE_CONNECTING	2
#define STATE_CONNECTED		3

#define MAX_CONNECT_SECONDS	10
#define MAX_SILENT_SECONDS	30

class	ME_Server;
class	ME_ServerClient;

#define	ME_BUFFER_TYPE_WRITE	(1)
#define	ME_BUFFER_TYPE_READ		(2)

// Replaced by ME_IO_THINK_*

#define	ME_NEXT_THINK_NONE			(0)	//	The code haven't requested the next think, if this is unset when the think function ends, there is a bug.
#define	ME_NEXT_THINK_WINCALLBACK	(1)	//	A completion callback has been requested from Windows.
#define	ME_NEXT_THINK_MECALLBACK	(2)	//	A completion callback has been requested from another ME_ServerClient service.
#define	ME_NEXT_THINK_WAIT			(3)	//	Wait NextThinkParam miliseconds then call me.
#define	ME_NEXT_THINK_DONT			(4)	//	Stop thinking!
#define	ME_NEXT_THINK_THINKAGAIN	(5)	//	Upon the think's completion, think again.

#define ScheduleNextThink(Type) ScheduledNextThink(Type,__LINE__,(char*)__FUNCTION__, __FILE__ );

STRUCTLINK OVERLAPPED_PLUS : public OVERLAPPED
{
	ME_ServerClient*	Client;
	ME_Server*			Server;
	int					BufferType; // ME_BUFFER_TYPE_*
};

class ME_Server;

CLASSLINK ME_ServerClient
{
public:
			ME_ServerClient();
	virtual	~ME_ServerClient();

public:
	//unsigned long		nWritten;
	//int					nInBufferSize;
	//TODO: REMOVE THIS:
	//WSABUF				buf_out_wsa;
	//CAutoBuffer*		buf_out;		// Data that is to be sent to client
	//char*				buf_in_actual;
	//char*				buf_out_actual;
	//size_t				buf_in_offset;
	//size_t				buf_in_used;
	ME_Buffer*			Input;
	ME_Buffer*			Output;
	OVERLAPPED_PLUS		In;
	OVERLAPPED_PLUS		Out;
	CRITICAL_SECTION	MayExecThinkFunction; // Thread Safety.
	sockaddr_in			LocalAddr;
	sockaddr_in			RemoteAddr;
	time_t				dTimeStamp;

	//void				InitializeInUse();
	//void				DeleteInUse();
	void				TimeStamp();
	time_t				SecondsElapsed();

public:

	ME_Server*			Server;					// Pointer to the server class that created us!
	//static int			nID;
	//int					nSpecificID;
	SOCKET				Socket;					// Socket used to communicate with client
	int					State();					// Current state of instance
	int					Mode();
	int					Command();
	void				SetMode(int NewMode);
	void				SetCommand(int NewCommand);
	void				SetState(int NewState);
	int					m_Mode;
	int					m_Command;
	int					m_State;
	int					NextThink;
	int					NextThinkParam;
	int					IsWriting;				// Are there data underway?
	int					IsReading;				// Are there data underway?
	bool				IsThinking;				// Are we currently thinking?
	bool				ShouldDisconnect;
	//unsigned long		nRead;
	char*				RemoteHost;
	short				RemotePort;
	// TODO: Update this values!
	size_t				DownSpeed;				// How fast are we recieving data
	size_t				UpSpeed;				// How fast are we sending data

	size_t				PeerId;					//	Unique per-class-instance-per-server identifier.

	virtual		void CALLBACK DoneIO(DWORD dwErrorCode,
						 DWORD dwNumberOfBytesTransferred,
						 LPOVERLAPPED lpOverlapped);


	virtual		bool		Init();				// Attach to a new client
	virtual		bool		Close();				// Detach from a client
	virtual		bool		InitializeBuffers();
	virtual		bool		TerminateBuffers();
	virtual		bool		ScheduledNextThink(int NextThinkType, int Line, char* Function, char* FileName);
	virtual		bool		Think();
	virtual		bool		DoThink();
	virtual		bool		Connect(char* Host);
	virtual		bool		Connected();
	virtual		bool		Disconnected();
	virtual		bool		Write(char* Buffer, size_t BufferLen);
	virtual		bool		Read(size_t Keep); // Read more data, but keep the last Keep bytes of the previous read.
	//virtual		bool		Write(tagPacket *p);	// Add a packet to output buffer
	//virtual		bool		Read(char* Buffer, size_t BufferLen);	// Retrieve a packet from input buffer
	//virtual		bool		OnRecieved(size_t Length); // When Length bytes are recieved
	//virtual		bool		NetWrite();			// Do actual send
	virtual		bool		Disconnect();
	virtual		bool		MaintainConnection();

	virtual		void		OnConnectionAccepted();	// Move from ACCEPTING to CONNECTED state
	
	//virtual		size_t		IN_BUFFER_SIZE( void );
	//virtual		size_t		IN_BUFFER_INC( void );
	//virtual		size_t		OUT_BUF_SIZE( void );

	virtual		void		Maintenance();						// Maintenance
};

//CLASSLINK ME_HTTPServerClient : public ME_ServerClient
//{
//	Declare_Class(ME_HTTPServerClient, ME_ServerClient);

//public:
//	ME_HTTPServerClient();
//	~ME_HTTPServerClient();

//public:
//	virtual		bool	WriteHTTP(char* Buffer, size_t BufferLen);
//	virtual		bool	WriteHTTPHeaders( void );
//	virtual		bool	Init();				// Attach to a new client
//	virtual		bool	Close();				// Detach from a client
//	virtual		bool	OnRecieved(size_t Length); // When Length bytes are recieved
//				int		ResponseCode;
//	virtual		bool	SetResponseCode(int NewResponseCode);
//	virtual		int		GetResponseCode();
//				char*	ContentType;
//	virtual		bool	SetContentType(char* NewContentType);
//	virtual		char*	GetContentType();
//				char*	ContentDisposition;
//	virtual		bool	SetContentDisposition(char* NewContentDisposition);
//	virtual		char*	GetContentDisposition();
//				int		ContentLength;
//	virtual		bool	SetContentLength(int NewContentLength);
//	virtual		int		GetContentLength();
//				bool	IsHeadersSent;
//				List	Headers;
//				int		FileHandle;
//				long	FileSize;
//				long	Left;
//				char*	Data;

//};

CLASSLINK ME_Server // : public ME_Window // it's useful to have a baseclass, but do we really need one?
{
	//Declare_Class(ME_Server, ME_Window);
public:

			ME_Server();
	virtual	~ME_Server();

public:
	virtual	bool	RunServer(short Port) = 0;
	virtual	bool	RunServerEx(short Port, size_t NumConnections, size_t CheckTime) = 0;
	virtual	bool	ShutDown();
	virtual	char*	GetServerInformationHeader();
	virtual	char*	GetServerInformationLine();
	virtual	bool	HandleRequest(ME_ServerClient* Client, char* Parameter = 0) = 0;
	virtual	bool	OpenLogFile(char* Path);
	virtual bool	CloseLogFile();
	virtual bool	ClearLogFile();
	virtual bool	ClearLogFile(char* Path);
	virtual	bool	SetDebugMode(bool IsDebugMode);
	virtual	bool	GetDebugMode();
	//virtual	int		ClientWrote(ME_ServerClient* Client,DWORD dwNumberOfBytesTransferred,OVERLAPPED_PLUS *ov);
	//virtual	int		ClientRead(ME_ServerClient* Client,DWORD dwNumberOfBytesTransferred,OVERLAPPED_PLUS *ov);
	virtual	bool	Log(char* Event);
	virtual	bool	LogDebug(char* Event);
	virtual	bool	LinkToWindow(HWND Window);

public:
	HWND	WindowHWND;
	size_t	MaxConnections;
	size_t	MaintenanceTime;
	short	Port;
	SOCKET	Listener;
	bool	DebugMode;
	bool	ShouldMainLoop;
	bool	ShouldListen;
	HANDLE	LogFile;

	ME_ServerClient**	Clients;
};

#define ME_IOCPServer_MaxConnections (1000)
#define	ME_IOCPServer_MaintenanceTime (1000)

// Overlapped I/O: Completion Ports
CLASSLINK ME_IOCPServer : public ME_Server
{
	Declare_Class(ME_IOCPServer, ME_Server);

public:
			ME_IOCPServer();
	virtual	~ME_IOCPServer();

	virtual	bool	RunServer(short Port);
	virtual	bool	RunServerEx(short Port, size_t NumConnections, size_t CheckTime);
	virtual	bool	ShutDown();
	virtual	bool	HandleRequest(ME_ServerClient* Client, char* Parameter = 0);

	void CALLBACK	DoneIO(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped);

	virtual			ME_ServerClient*	CreateIOCPClient		(void);
	virtual			bool				OnClientCreated			(ME_ServerClient* Client);
	virtual			bool				OnClientConnected		(SOCKET s, int Errror);
	virtual			bool				OnClientDisconnected	(SOCKET s, int Errror);

public:
	HANDLE	TerminateEvent;
};

LINK	void CALLBACK		ME_ServerClient__DoneIO(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped);

//// Overlapped I/O: Completion Ports
//CLASSLINK ME_HTTPServer : public ME_IOCPServer
//{
//	Declare_Class(ME_HTTPServer, ME_IOCPServer);
//public:
//	ME_HTTPServer();
//	~ME_HTTPServer();

//public:
//	virtual	bool	HandleRequest(ME_ServerClient* Client, char* Parameter = 0);

//	virtual			ME_ServerClient*	CreateIOCPClient( void );
//};

//LINK	int					METestServer();

EndMaxsiNamespace

#endif
